home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 013 / vtree2.arc / VTREE2.DOC < prev   
Encoding:
Text File  |  1986-12-25  |  15.9 KB  |  409 lines

  1. (* VTREE  -  Written Feb 5, 1986 By Vinnie Finn
  2.                                    137 Falmouth St.
  3.                                    Rochester, NY 14615
  4.                                    (716) 663-0729
  5.              Modified Oct 11, 1986 By Vinnie Finn
  6.              add lines to output and enable output redirection.
  7.  
  8.   Recursive Program to display the tree structure of a disk.
  9.   can be modified to perform  -  Where   { Modify FileName='*.*' to input parameter}
  10.                                          { and Atrribute to 255 }
  11.                                  Tree/F  { Write All fileNames,Size,Date&Time}
  12.                                  Treed - { With Lines }
  13.  
  14.   This was written after curiousity was sparked by the TREED.EXE Program,
  15.   which performed the same way this program does but did not provide
  16.   code. I feel apprehensive about getting hooked on any code that can not
  17.   be modified by the user.
  18.  
  19.   Input parameter optional. Include path and directory of Tree to start
  20.   with, defaults to Root.
  21.  
  22.   I believe that the best way to learn program techniques, is to study
  23.   others programs.  I'm sure that this code is not the cleanest in the
  24.   world, so If anyone modifys it, I would appreciate a copy.
  25.   Upload the new file to Station Rochester, Rochester, NY.  The number
  26.   is (716)544-8327 Dave Stanwix,  Sysop.
  27.  
  28.   This program is put in the public domain under the shareware concept.
  29.   If you feel this program is worth a financial contribution to the 
  30.   development of new software, send a contribution of $3.00 or more to
  31.   my address above.  You will then be a registered owner and will be 
  32.   informed of new software releases for Vtree and more, as soon as they 
  33.   are available.  Thanks again, and remember... The Shareware concept is
  34.   users SUPPORTING users !!  Any comments about the software can be left
  35.   on Station Rochester PCBoard and will receive a prompt reply.
  36.  
  37.   The speed of this program can be enhanced by changing the stack structure
  38.   to a forward and backward, linked list. I just thought I'd play with a
  39.   recursive search (Dig).
  40.  
  41.   Redirection of Output may be used. This means that you can run this
  42.   program and redirect the output to the printer or a file or any other
  43.   device. The standard DOS format for this is application would be:
  44.   VTREE2>PRT
  45.   or
  46.   VTREE2>FileName.ext
  47.   and to append it to the end of a document or file.
  48.   VTREE2>>Filename.Ext
  49. *)
  50. {$P512}     { Enable Output re-direction }
  51. {$C-}       { Disable Control C }
  52.  
  53. Program VTree2;
  54. {****************************************************************************}
  55. {                  F I L E         S U B R O U T I N E S                     }
  56. {****************************************************************************}
  57.   Const   Hor  = '─';
  58.           Ver  = '│';
  59.           T    = '┬';
  60.           ST   = '├';
  61.           L    = '└';
  62.           Symbols : Array[Boolean,Boolean] Of Char = (('└','├'),('─','┬'));
  63.   Type
  64.     RegisterSet=Record Case Integer Of
  65.                   1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
  66.                   2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
  67.                 End;
  68.     DTAptr = ^Dir_Entry;
  69.     Buff       = record
  70.                       Reserved        : array[1..21] of byte;
  71.                       Attribute       : byte;
  72.                       Time,
  73.                       Date,
  74.                       FileSizeLo,
  75.                       FileSizeHi      : integer;
  76.                       Name            : string[13];
  77.                   end;
  78.     Dir_Entry   = Record
  79.                      Dta      : Buff;
  80.                      Level    : Byte;
  81.                      Next_Ptr : DtaPtr;
  82.                   End;
  83.     FileName_Type  = String[64];
  84. Var
  85.     Reg       : RegisterSet;  { Dos Registers                              }
  86.     TopBuff,                  { Pointer to the Top of The Linked list.     }
  87.     BuffPtr,
  88.     WorkPtr   : DtaPtr;       { Pointer to the current node within List.   }
  89.     RetCode   : byte;         { Return code, contains error code if any.   }
  90.     Tmp       : FileName_Type;{ Used to avoid collision.                   }
  91.     I,                        { General purpose variable.                  }
  92.     Fill_len  : Integer;      { Used to prohibit lines at end of line      }
  93.     Err       : Byte;         { Flags error on directory change/get.       }
  94.     PushDone  : Boolean;      { Tells if most recent thing done was a Push }
  95.     LowLevel  : Byte;         { Tells level of current BuffPtr within      }
  96.                               { linked list. How far from top.             }
  97.     Line,
  98.     Blank     : String[80];   { Contains Blanks.                           }
  99.  
  100.  
  101. {****************************************************************************}
  102. {                S  E  T       Disk  Transfer  Address                       }
  103. {****************************************************************************}
  104. Procedure Set_Disk_Trns_Addr(BuffPtr:DtaPtr);
  105. Begin
  106.   with Reg do
  107.   begin
  108.       Ax := $1A00;                     { Set disk transfer address to  }
  109.       Ds := seg(BuffPtr^.dta);             { our disk buffer               }
  110.       Dx := ofs(BuffPtr^.dta);
  111.       MsDos(Reg);
  112.   end;
  113. end;
  114.  
  115. {****************************************************************************}
  116. {                 P U S H   B U F F E R   O N T O   S T A C K                }
  117. {****************************************************************************}
  118. PROCEDURE PushBuff;    { Saves current DTA Area and sets up for a new one }
  119. BEGIN
  120.     PushDone:=True;
  121.     new( BuffPtr^.Next_Ptr );
  122.     BuffPtr:=BuffPtr^.Next_Ptr;
  123.     If TopBuff=Nil Then TopBuff:=BuffPtr;
  124.     LowLevel:=LowLevel+1;
  125.     BuffPtr^.Level:=LowLevel;
  126.     Set_Disk_Trns_Addr(BuffPtr);
  127. END; {Push_Buff}
  128.  
  129. {****************************************************************************}
  130. {            Dig down to the Lowest Level of the Heap                        }
  131. {****************************************************************************}
  132. Function Dig(Point:DtaPtr):DtaPtr;   { Recursive find of pointer }
  133. Begin
  134.    If Point^.Level>=LowLevel Then    { Go as deep as is the Heap }
  135.       Dig:=Point
  136.    Else
  137.       Dig:=Dig(Point^.Next_Ptr);
  138. End;
  139.  
  140. {****************************************************************************}
  141. {                         Pop Prior DTA off the Heap                         }
  142. {****************************************************************************}
  143. PROCEDURE PopBuff;         { Pop off the previously Pushed DTA Area }
  144. Var  FreePoint: DTAPtr;
  145. BEGIN {RestoreBuff}
  146.   FreePoint:=BuffPtr;
  147.   PushDone:=False;
  148.   Reg.AH:=$2F;
  149.   MsDos(Reg);
  150.   LowLevel:=LowLevel-1;
  151.   BuffPtr:=Dig(TopBuff);
  152.   Set_Disk_Trns_Addr(BuffPtr);
  153.   Dispose(FreePoint);  { Free un-needed node on the Heap }
  154. END; {Pop_Buff}
  155.  
  156.  
  157.  
  158.  
  159. {****************************************************************************}
  160. {                  F I N D   N E X T   F I L E   E N T R Y                   }
  161. {****************************************************************************}
  162. Procedure Find_Next(var Att:byte; var Filename : Filename_type;
  163.                                       var Next_RetCode : byte);
  164. var
  165.   Carry_flag : integer;
  166.   N          : byte;
  167.  
  168. Begin  {Find_Next}
  169.   BuffPtr^.Dta.Name := '             ';     { Clear result buffer }
  170.   With Reg do
  171.   Begin
  172.       Ax := $4F shl 8;                 { Dos Find next function }
  173.       MsDos(Reg);
  174.       Att := BuffPtr^.Dta.Attribute;         { Set file attribute     }
  175.       Carry_flag := 1 and Flags;       { Isolate the Error flag }
  176.       Filename := '             ';
  177.       if Carry_flag = 1 then
  178.         Next_RetCode := Ax and $00FF
  179.       else
  180.       begin                          { Move file name         }
  181.         Next_RetCode := 0;
  182.         for N := 0 to 12 do
  183.            FileName[N+1] := BuffPtr^.Dta.Name[N];
  184.       end;
  185.   end;  {with}
  186. end;
  187. {****************************************************************************}
  188. {              F I N D   F I R S T   F I L E   F U N C T I O N               }
  189. {****************************************************************************}
  190. Procedure Find_First (var Att: byte;
  191.                       var Filename: Filename_type;
  192.                       var RetCode_code : byte);
  193.  
  194.   var
  195.  
  196.       Carry_flag       :integer;
  197.       Mask, N          :byte;
  198.  
  199.   begin
  200.     Set_Disk_Trns_Addr(BuffPtr);
  201.     Filename[length(Filename) + 1] := chr(0);
  202.     BuffPtr^.Dta.Name := '             ';
  203.     with Reg do
  204.     begin
  205.       Ax := $4E shl 8;                  { Dos Find First Function }
  206.       Cx := Att;                        { Attribute of file to fine }
  207.       Ds := seg(Filename);              { Ds:Dx Asciiz string to find }
  208.       Dx := ofs(Filename) + 1;
  209.       MsDos(Reg);
  210.       Att := BuffPtr^.Dta.Attribute;          { set the file attribute byte  }
  211.                  { If error occured set, Return code. }
  212.       Carry_flag := 1 and Flags;      { If Carry flag, error occured }
  213.                                         { and Ax will contain Return code }
  214.       if Carry_flag = 1 then
  215.           RetCode_code := Ax and $00FF
  216.       else
  217.       begin
  218.           RetCode_code := 0;
  219.           Filename := '             ';
  220.           for N := 0 to 12 do
  221.              FileName[N+1] := BuffPtr^.Dta.Name[N];
  222.       end;
  223.    End;
  224. end;
  225.  
  226. {****************************************************************************}
  227. {         Asciiz changes a IBM formatted string into an Asciiz formatted     }
  228. {         string.  IBM = [Length]+[Ch]+[Ch]+[Ch]...                          }
  229. {               AsciiZ = [Ch]+[Ch]+[Ch]...0                                  }
  230. {****************************************************************************}
  231. Procedure Asciiz(VAR Inp : FileName_Type);
  232. VAR  L,Indx   : Integer;
  233. Begin
  234.    L:=Length(Inp);
  235.    If L>0 Then
  236.       For Indx:=0 to L-1 Do
  237.          Inp[Indx]:=Inp[Indx+1];
  238.    Inp[L]:=#0;
  239. End;
  240.  
  241. {****************************************************************************}
  242. {                  DOS Call for current directory and Path                   }
  243. {****************************************************************************}
  244. Function Get_Curr_Dir : FileName_Type;
  245. begin
  246.       Reg.AH:=$47;                 { Get Current directory }
  247.       Reg.Ds:=Seg(Tmp);
  248.       Reg.Si:=Ofs(Tmp)+1;     { Bypass the length Byte }
  249.       Reg.DL:=$0;
  250.       Msdos(Reg);
  251.       If (Reg.Flags And 1)=1 Then  { Carry flag is set }
  252.          Err:=Reg.AX
  253.       Else
  254.       Begin
  255.          I:=1;
  256.          While Tmp[I]<>#0 Do
  257.             I:=I+1;
  258.          Tmp[0]:=Chr(I);     { Adjust Length of string }
  259.          Get_Curr_dir:=Tmp;
  260.       End;
  261. End;
  262.  
  263. {****************************************************************************}
  264. {                  DOS Call to Change Current directory                      }
  265. {****************************************************************************}
  266. Procedure Change_Dir(Directory:FileName_Type);
  267. Begin
  268.     Tmp:=Directory;
  269.     Asciiz(Tmp);
  270.     Reg.AH:=$3B;
  271.     Reg.DS:=Seg(Tmp);
  272.     Reg.DX:=Ofs(Tmp);
  273.     MsDos(Reg);
  274.     If (Reg.Flags And 1)=1 Then  { Carry flag is set }
  275.        Err:=Reg.AX;
  276. End;
  277.  
  278.  
  279. {****************************************************************************}
  280. {                       P R O C E S S     D I R E C T O R Y                  }
  281. {                                                                            }
  282. {   This is a recursive program to  1) Make a New DTA working area           }
  283. {                                   2) Find First  *                         }
  284. {                                   3) Find Next   *                         }
  285. {                                   4) Return to Prior DTA Stack condition.  }
  286. {   *  If File=Directory  A) Write Directory Name.                           }
  287. {                         B) Call Process Directory.                         }
  288. {****************************************************************************}
  289. var
  290.   attribyte    : Byte;
  291.   Curr_Dir,
  292.   Save_Dir     : fileName_Type;
  293.  
  294. Procedure Process_Dir(Dir:FileName_Type);
  295. Var      Filename  : FileName_Type;
  296.          Lngth     : Integer;
  297.          Curr_Sym  : Char;
  298.          First     : Boolean;
  299.     Procedure Hit_Check;
  300.     Var Fil  : FileName_Type;
  301.         Att,
  302.         Ret  : Byte;
  303.         Sym  : Char;
  304.     Begin
  305.        If (Retcode = 0)  then  { No error }
  306.           { subdirectory only but not '.' or '..' }
  307.           If (Attribyte=$10) AND (FileName[1]<>'.') Then
  308.           Begin
  309.              If (NOT PushDone) AND (LowLevel>1) Then
  310.                 Write(' ',Copy(Blank,1,10*(LowLevel-1))) { Tab over }
  311.              Else
  312.                 If (LowLevel=1) And (Not First) Then
  313.                    Write(' ')
  314.                 Else
  315.                    Write(Hor);
  316.              Lngth:=Pos(' ',FileName)-2;
  317.              { The only way that I can figure out which lines are to be  }
  318.              { used is to look ahead in the same directory for a Sub Dir.}
  319.              { This slows down the program somewhat because it repeats   }
  320.              { this find when we move down the DIR. But my brain was     }
  321.              { turning to mush at this point. VTREE3 will contain the    }
  322.              { enhancement that will avoid this duplicate processing.    }
  323.              Att:=Attribyte;      { Do not destroy current Attributes    }
  324.              Ret:=RetCode;
  325.              Fil:=FileName;
  326.              WorkPtr^.DTA:=BuffPtr^.DTA; { Copy current Buffer to work buffer }
  327.              PushBuff;                   { Save Current buffer                }
  328.              BuffPtr^.Dta:=WorkPtr^.Dta; { Copy previous buffer to current    }
  329.              Repeat
  330.                 Find_Next(att,fil,Ret);
  331.              Until (Att=$10) AND (Fil[1]<>'.') OR (Ret<>0);
  332.              Sym:=Symbols[First,Ret=0];   { Quick way to do the following }
  333. (*           If First Then
  334.              Begin
  335.                 If Ret=0 Then    { No Error }
  336.                    Sym:=T    { Is another Dir following }
  337.                 Else
  338.                    Sym:=Hor; { End of Sub Dirs for this Dir }
  339.              End
  340.              Else
  341.              Begin
  342.                 If Ret=0 Then
  343.                    Sym:=St
  344.                 Else
  345.                    Sym:=L;
  346.              End;
  347. *)
  348.              Write(Copy(Line,1,Fill_len),Sym,Copy(Filename,1,Lngth));
  349.              Fill_Len:=8-Lngth;
  350.              PopBuff;          { Set current back to previous buffer }
  351.              First:=False;
  352.              Process_Dir(FileName);
  353.              Fill_Len:=0;
  354.           End;
  355.     End; { Hit Check }
  356. Begin
  357.       PushBuff;
  358.       Change_Dir(Dir);
  359.       filename := '*.*' ;
  360.       attribyte := $10;     { Normal + SubDirectories }
  361.       Retcode:=0;
  362.       First:=True;
  363.       Find_First(attribyte,filename,Retcode);
  364.       Hit_Check;
  365.       {Now we repeat Find_Next until an error occurs }
  366.       Repeat
  367.          Find_Next(attribyte,filename,Retcode);
  368.          Hit_Check;
  369.       Until Retcode <> 0;    { Until Error = mostlikely error will be #18 (No More Files) }
  370.       If PushDone Then WriteLn;
  371.       PopBuff;                    { Back Out }
  372.       Change_Dir('..');
  373.       RetCode:=0;
  374. End;
  375.  
  376.  
  377. {***************************************************************************}
  378. {                          M A I N    L I N E                               }
  379. {***************************************************************************}
  380.  
  381.   begin
  382.        New(WorkPtr);
  383.        TopBuff:=Nil;
  384.        BuffPtr:=Nil;
  385.        For I:=1 to 80 Do
  386.           Line[I]:=Hor;      { Maybe make it a constant ! }
  387.        Blank[1]:=Ver;
  388.        For I:=2 to 80 Do
  389.           Blank[I]:=' ';
  390.        Line[0]:=Chr(80);    { Set length }
  391.        Blank[0]:=Chr(80);
  392.        LowLevel:=0;
  393.        Fill_Len:=0;
  394.        ClrScr;
  395.        Save_Dir:=Get_Curr_Dir;
  396.        If (Reg.Flags And 1)=1 then Halt;
  397.        Err:=0;
  398.        If ParamCount>0 Then
  399.        Begin
  400.           Curr_Dir:=ParamStr(1);
  401.           WriteLN(Curr_Dir);WriteLN;
  402.        End
  403.        Else
  404.           Curr_Dir:='\';
  405.        Process_Dir(Curr_Dir);
  406.        Change_Dir('\'+Save_Dir);
  407.        Dispose(WorkPtr);
  408.   end.
  409.